package org.movsim.simulator.vehicles;

import java.io.File;

import org.movsim.autogen.VehiclePrototypeConfiguration;
import org.movsim.simulator.B5Constants;
import org.movsim.simulator.B5Constants.B5_PSYCOLOGICAL_FACTORS;
import org.movsim.simulator.B5Constants.INPUT_FROM_ENVIRONMENT;
import org.movsim.simulator.Configuration;
import org.movsim.simulator.MovsimConstants;
import org.movsim.simulator.pslogger.PSLogger;
import org.movsim.simulator.roadnetwork.RoadSegment;
import org.movsim.simulator.vehicles.lanechange.LaneChangeModel;
import org.movsim.simulator.vehicles.longitudinalmodel.acceleration.LongitudinalModelBase;

public class PSEnabledVehicle extends Vehicle {

    private double[] positiveB5States = new double[B5_PSYCOLOGICAL_FACTORS.values().length];
    private double[] negativeB5States = new double[B5_PSYCOLOGICAL_FACTORS.values().length];
    
    public File f = null;
    private static int pCount = 0;
    
    public final double STABLE_SPEED_DIFFERENCE = 2.5;

    private Environment env;
    private double distanceFromSignal = MovsimConstants.GAP_INFINITY;

    public double getDistanceFromSignal() {
        return distanceFromSignal;
    }
    
    public void setDistanceFromSignal(double distanceFromSignal) {
        this.distanceFromSignal = distanceFromSignal;
    }
    
    public Environment getEnv(){
        return env;
    }

    public PSEnabledVehicle(Vehicle source) {
        super(source);
        // TODO Auto-generated constructor stub
        intilize();
        
    }

    public PSEnabledVehicle(String label, LongitudinalModelBase longitudinalModel,
            VehiclePrototypeConfiguration vehInput, LaneChangeModel lcModel) {
        super(label, longitudinalModel, vehInput, lcModel);
        // TODO Auto-generated constructor stub
        intilize();
    }

    public PSEnabledVehicle(double rearPosition, double speed, int lane, double length, double width) {
        super(rearPosition, speed, lane, length, width);
        // TODO Auto-generated constructor stub
        intilize();
    }
    
    private void intilize() {

        env = new Environment(this);

        double[][] t = B5Constants.readInitialPsychologicalState();
        positiveB5States = t[0];
        negativeB5States = t[1];
        
        if (Configuration.LOG_TEMPORAL_PSYCHOLOGICAL_STATE) {
            f = new File(Configuration.PSY_STATE_TRACE_OUT_PATH + "/" + pCount++ + ".csv");
            PSLogger.initilizeFile(f);
        }

    }

    public double[] getCumulativePsyStates() {
        double[] retval = new double[B5_PSYCOLOGICAL_FACTORS.values().length];
        for (B5_PSYCOLOGICAL_FACTORS e : B5_PSYCOLOGICAL_FACTORS.values()) {
            retval[e.ordinal()] = positiveB5States[e.ordinal()] - negativeB5States[e.ordinal()];
        }
        return retval;
    }

    public double[] computeEnvironmentB5Input(RoadSegment roadSegment) {
        double[] eB5 = new double[B5_PSYCOLOGICAL_FACTORS.values().length];
        for (INPUT_FROM_ENVIRONMENT e : INPUT_FROM_ENVIRONMENT.values()) {
            double degree = env.getDegreeOfEnvironment(e, roadSegment);
            for (B5_PSYCOLOGICAL_FACTORS p : B5_PSYCOLOGICAL_FACTORS.values()) {
                eB5[p.ordinal()] += degree * B5Constants.getB5EnvironmentValue(e, p);
            }
        }
        for (int i = 0; i < eB5.length; ++i) {
            eB5[i] = eB5[i] / INPUT_FROM_ENVIRONMENT.values().length;
        }
        return eB5;
    }

    public void updatePsychologicalState(RoadSegment roadSegment) {
        double[] eB5 = computeEnvironmentB5Input(roadSegment);
        for (B5_PSYCOLOGICAL_FACTORS p : B5_PSYCOLOGICAL_FACTORS.values()) {
            if (eB5[p.ordinal()] > 0) {
                positiveB5States[p.ordinal()] = positiveB5States[p.ordinal()] + (1 - positiveB5States[p.ordinal()])
                        * eB5[p.ordinal()];
            } else if (eB5[p.ordinal()] < 0) {
                negativeB5States[p.ordinal()] = negativeB5States[p.ordinal()] - (1 - negativeB5States[p.ordinal()])
                        * eB5[p.ordinal()];
            }
        }
    }

    public void resetPsychogicalVeriables() {
        distanceFromSignal = MovsimConstants.GAP_INFINITY;
    }
}
